package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountService;
import cn.itcast.account.service.TCCAccountService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Author: ahcfl
 * @Date: 2021年07月27日 19:44
 * @Description:
 */
@Service
public class TccAccountServiceImpl implements TCCAccountService {

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountFreezeMapper accountFreezeMapper;

    @Autowired
    private AccountMapper accountMapper;

    @Override
    @Transactional
    public void tryDeduct(String userId, int money) {
        // 获取全局事务id
        String xid = RootContext.getXID();

        // 判断当前事务 的cancel是否已经执行
        AccountFreeze oldFreeze = accountFreezeMapper.selectById(xid);
        if(oldFreeze != null){
            // 说明已经空回滚了  为了避免 业务 悬挂 ，就不能执行了
            return;
        }

        // 1.扣减可用余额
        accountService.deduct(userId, money);

        // 2.新增冻结金额及事务记录到tb_freeze_account
        AccountFreeze accountFreeze = new AccountFreeze();
        accountFreeze.setXid(xid);
        accountFreeze.setUserId(userId);
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setState(AccountFreeze.State.TRY);
        accountFreezeMapper.insert(accountFreeze);

    }


    @Override
    public boolean confirm(BusinessActionContext ctx) {
        String xid = ctx.getXid();
        int count = accountFreezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        // 1.事务回滚 恢复余额
        String xid = ctx.getXid();
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        String userId = ctx.getActionContext("userId").toString();
        Integer money = (Integer) ctx.getActionContext("money");
        accountMapper.refund(userId, money);

        // 判断空回滚
        if(accountFreeze == null){
            // try阻塞  尚未执行  插入一条空冻结操作记录  证明空回滚了
            AccountFreeze accountFreeze2 = new AccountFreeze();
            accountFreeze2.setXid(xid);
            accountFreeze2.setUserId(userId);
            accountFreeze2.setFreezeMoney(0);
            accountFreeze2.setState(AccountFreeze.State.CANCEL);
            accountFreezeMapper.insert(accountFreeze2);
            return true;
        }

        // 判断业务幂等性  如果是重复业务 就不再执行
        if(accountFreeze.getState() == AccountFreeze.State.CANCEL){
            return true;
        }


        // 2. 冻结操作
        accountFreeze.setFreezeMoney(0);
        accountFreeze.setState(AccountFreeze.State.CANCEL);
        int count = accountFreezeMapper.updateById(accountFreeze);
        return count == 1;
    }
}
